package xin.tianhui.cloud.weblog.service.impl;

import xin.tianhui.cloud.weblog.model.dto.ChannelResultDTO;
import xin.tianhui.cloud.weblog.model.dto.ChannelTxtResultDTO;
import xin.tianhui.cloud.weblog.model.dto.ChannelAttrResultDTO;
import xin.tianhui.cloud.weblog.model.dto.ChannelQueryDTO;
import xin.tianhui.cloud.weblog.model.dto.ModelResultDTO;
import xin.tianhui.cloud.weblog.model.po.Channel;
import xin.tianhui.cloud.weblog.core.model.dto.PagingDTO;
import xin.tianhui.cloud.weblog.core.model.vo.PagingVO;
import xin.tianhui.cloud.weblog.mapper.ChannelMapper;
import xin.tianhui.cloud.weblog.service.IChannelAttrService;
import xin.tianhui.cloud.weblog.service.IChannelService;
import xin.tianhui.cloud.weblog.service.IChannelTxtService;
import xin.tianhui.cloud.weblog.service.IModelService;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.sql.SqlHelper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.dozer.Mapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import static xin.tianhui.cloud.weblog.constant.Constants.MAPPER_CHANNEL_ID;

/**
 * <p>
 * 栏目表 服务实现类
 * </p>
 *
 * @author junchen
 * @since 2018-04-06
 */
@Service
@CacheConfig(cacheNames="channel",keyGenerator="keyGenerator")
public class ChannelServiceImpl extends ServiceImpl<ChannelMapper, Channel> implements IChannelService {
	
	@Autowired
	private Mapper mapper;
	
	@Autowired
	private IModelService modelService;
	
	@Autowired
	private IChannelAttrService channelAttrService;
	
	@Autowired
	private IChannelTxtService channelTxtService;
	
	@Cacheable(key="'path:'+#path")
	@Override
	public ChannelResultDTO getChannelByPath(String path) {
		Channel entity = new Channel();
		entity.setIsDisplay(1);
		entity.setPath(path);
		QueryWrapper<Channel> wrapper = new QueryWrapper<>(entity);
		Channel channel = baseMapper.selectOne(wrapper);
		if(channel!=null) {
			ChannelResultDTO dto = new ChannelResultDTO();
			channelBuilder(channel, dto);
			List<ChannelAttrResultDTO> attrs = channelAttrService.getChannelAttrs(channel.getId());
			Map<String,String> attr = Optional.ofNullable(attrs).map(result->{
				Map<String,String> map = Maps.newHashMap();
				result.forEach(r->{
					map.put(r.getName(), r.getValue());
				});
				return map;
			}).orElse(Maps.newHashMap());
			dto.setAttr(attr);
			ModelResultDTO model = modelService.getModel(channel.getModelId());
			dto.setModel(model);
			List<ChannelTxtResultDTO> txtResultDTOs = channelTxtService.getChannelTxt(channel.getId());
			if(CollectionUtils.isNotEmpty(txtResultDTOs)) {
				dto.setContent(txtResultDTOs.get(0));
			}
			return dto;
		}
		return null;
	}
	
	@Cacheable(key="'id:'+#bid")
	@Override
	public ChannelResultDTO getChannelById(Integer bid) {
		Channel entity = new Channel();
		entity.setIsDisplay(1);
		entity.setId(bid);
		QueryWrapper<Channel> wrapper = new QueryWrapper<>(entity);
		Channel channel = baseMapper.selectOne(wrapper);
		if(channel!=null) {
			ChannelResultDTO dto = new ChannelResultDTO();
			channelBuilder(channel, dto);
			List<ChannelAttrResultDTO> attrs = channelAttrService.getChannelAttrs(channel.getId());
			Map<String,String> attr = Optional.ofNullable(attrs).map(result->{
				Map<String,String> map = Maps.newHashMap();
				result.forEach(r->{
					map.put(r.getName(), r.getValue());
				});
				return map;
			}).orElse(Maps.newHashMap());
			dto.setAttr(attr);
			ModelResultDTO model = modelService.getModel(channel.getModelId());
			dto.setModel(model);
			List<ChannelTxtResultDTO> txtResultDTOs = channelTxtService.getChannelTxt(channel.getId());
			if(CollectionUtils.isNotEmpty(txtResultDTOs)) {
				dto.setContent(txtResultDTOs.get(0));
			}
			return dto;
		}
		return null;
	}
	
	@Cacheable
	@SuppressWarnings("unchecked")
	@Override
	public PagingVO<ChannelResultDTO> channelPaging(PagingDTO paging, ChannelQueryDTO channelQuery) {
		String sidx = paging.getSidx();
		String sord = paging.getSord();
		String orderByField = null;
		boolean asc = false;
		if(StringUtils.isNotBlank(sidx) && StringUtils.isNotBlank(sord)) {
			if(sidx.equals("priority")) {
				orderByField = "priority";
			}
			asc  = sord.toUpperCase().equals("ASC");
		}
		Page<Channel> page = new Page<>(paging.getPage(), paging.getRows());
		if(asc) {
			page.setAscs(orderByField);
		}else {
			page.setDescs(orderByField);
		}
		
		Channel channel = new Channel();
		QueryWrapper<Channel> entityWrapper = new QueryWrapper<>(channel);
		entityWrapper.and(channel.getParentId()==null, i-> i.isNull("parent_id"));
		Wrapper<Channel> wrapper = (Wrapper<Channel>) SqlHelper.fillWrapper(page, entityWrapper);
		IPage<Channel> channels = baseMapper.selectPage(page, wrapper);
        List<ChannelResultDTO> rows = Optional.ofNullable(channels).map(result->{
        	List<ChannelResultDTO> dtos = Lists.newArrayList();
			result.getRecords().forEach(r->{
				ChannelResultDTO dto = new ChannelResultDTO();
				channelBuilder(r,dto);
				dtos.add(dto);
			});
        	return dtos;
        }).orElse(Collections.emptyList());
        PagingVO<ChannelResultDTO> pagingVO = new PagingVO<>(rows, page.getPages(), page.getCurrent(), page.getTotal());
		return pagingVO;
	}
	
	@Cacheable(key="'parentId:'+#parentId")
	@Override
	public List<ChannelResultDTO> channelchildren(Integer parentId) {
		Channel channel = new Channel();
		channel.setIsDisplay(1);
		QueryWrapper<Channel> wrapper = new QueryWrapper<>(channel);
		wrapper.and(parentId == 0, i-> i.isNull("parent_id"));
		wrapper.and(parentId != 0,i-> i.eq("parent_id", parentId));
		List<Channel> channels = baseMapper.selectList(wrapper);
		List<ChannelResultDTO> resultDtos = Optional.ofNullable(channels).map(result->{
        	List<ChannelResultDTO> dtos = Lists.newArrayList();
			result.forEach(r->{
				ChannelResultDTO dto = new ChannelResultDTO();
				channelBuilder(r,dto);
				QueryWrapper<Channel> wrapper2 = new QueryWrapper<>();
				wrapper2.and(i-> i.eq("parent_id",r.getId()));
				Integer count = baseMapper.selectCount(wrapper2);
				dto.setLeaf(count == 0);
				dtos.add(dto);
			});
        	return dtos;
        }).orElse(Collections.emptyList());
		return resultDtos;
	}
	
	private void channelBuilder(Channel channel,ChannelResultDTO dto) {
		mapper.map(channel, dto,MAPPER_CHANNEL_ID);
	}
	
	@Cacheable
	@Override
	public List<ChannelResultDTO> getChannelList() {
		return getChannelList(0);
	}
	
	private List<ChannelResultDTO> getChannelList(Integer parentId){
		Channel channel = new Channel();
		channel.setIsDisplay(1);
		QueryWrapper<Channel> wrapper = new QueryWrapper<>(channel);
		wrapper.and(parentId == 0, i-> i.isNull("parent_id"));
		wrapper.and(parentId != 0,i-> i.eq("parent_id", parentId));
		List<Channel> channels = baseMapper.selectList(wrapper);
		return Optional.ofNullable(channels).map(result->{
        	List<ChannelResultDTO> dtos = Lists.newArrayList();
			result.forEach(r->{
				ChannelResultDTO dto = new ChannelResultDTO();
				channelBuilder(r,dto);
				dto.setChilds(getChannelList(r.getId()));
				if(CollectionUtils.isEmpty(dto.getChilds())) {
					dto.setLeaf(true);
					dto.setChilds(null);
				}else {
					dto.setLeaf(false);
				}
				dtos.add(dto);
			});
        	return dtos;
        }).orElse(Collections.emptyList());
	}

}
